﻿using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Xml.Linq;
using ztymodbus;

public static class AlarmQueue
{
    // 1. 定义参数类 (与之前相同)
    public class AlarmData
    {
        public string Name { get; set; }
        public string Content { get; set; }
        public string SendStaff { get; set; }
        public DateTime AddTime { get; set; }
    }

    // 2. 核心：BlockingCollection 负责线程安全和阻塞/唤醒
    // 内部默认使用 ConcurrentQueue
    private static readonly BlockingCollection<AlarmData> _queue = new();

    // 3. 消费者任务，保持任务引用
    private static Task _consumerTask;

    // 4. 假设您的数据库连接对象是静态且线程安全的，或者您可以将其传递进来
    // **重要**：如果 conn 是实例对象，请调整为静态或传入
    // public static object conn; 

    // 5. 初始化方法：启动消费者任务
    public static void Initialize()
    {
        // 保证消费者任务只启动一次
        if (_consumerTask == null || _consumerTask.IsCompleted)
        {
            // 在一个独立的后台线程中运行 ConsumerLoop
            _consumerTask = Task.Run(() => ConsumerLoop());
        }
    }

    // 6. 生产者方法：所有调用都通过这个方法进入队列
    public static void EnqueueAlarm(string name, string content, string send_staff, DateTime add_time)
    {
        var data = new AlarmData
        {
            Name = name,
            Content = content,
            SendStaff = send_staff,
            AddTime = add_time
        };

        // Add 方法是线程安全的，将数据放入队列
        _queue.Add(data);
    }

    // 7. 消费者循环 (简单且可靠)
    private static void ConsumerLoop()
    {
        // GetConsumingEnumerable() 会在队列为空时自动阻塞线程，直到有新项加入。
        // 这是 BlockingCollection 最强大的特性。
        foreach (var alarmData in _queue.GetConsumingEnumerable())
        {
            // 每次循环只处理一项，保证了任务的严格串行执行
            ProcessAlarmData(alarmData);
        }
    }

    // 8. 实际执行数据库操作的方法
    private static void ProcessAlarmData(AlarmData alarmData)
    {
        Conn conn = new();
        Code code = new();

        // 🚨 强烈建议在这里使用 try-catch，并记录异常 🚨
        try
        {
            try
            {
                List<SqlParameter> list_SP = new();
                list_SP.Add(new SqlParameter("id", Guid.CreateVersion7()));
                list_SP.Add(new SqlParameter("name", alarmData.Name));
                list_SP.Add(new SqlParameter("content", alarmData.Content));
                list_SP.Add(new SqlParameter("send_staff", alarmData.SendStaff));
                list_SP.Add(new SqlParameter("add_time", alarmData.AddTime));

                SqlParameter[] sp = list_SP.ToArray();

                IDataReader dr = conn.SelectSql("  select top 1 * from [Alarm_iot_list] WITH(UPDLOCK) where [name]=@name and [content]=@content and datediff(minute,add_time,getdate())<10 and [status]=1 order by id desc", sp);
                if (!dr.Read())
                {

                    conn.InsertSql_uuid(" insert into [Alarm_iot_list]  WITH(UPDLOCK) ([id],[name],[content],[send_staff],[add_time]) values(@id , @name , @content , @send_staff , @add_time )  ", sp);
                }
            }
            catch (Exception ex)
            {
                code.Into_Blog("写入报警日志出错:" + ex.ToString() + "<br/><br/>name:" + alarmData.Name + "<br/>content:" + alarmData.Content + "<br/>send_staff:" + alarmData.SendStaff + "<br/>add_time:" + alarmData.AddTime, 1, "Alarm", 0);
            }
        }
        catch (Exception ex)
        {
            // 如果日志写入也失败，至少可以在控制台或调试输出中看到
            System.Diagnostics.Debug.WriteLine($"Alarm Queue Error: {ex}");
            code.Into_Blog("写入报警日志出错:" + ex.ToString() + "...", 1, "Alarm", 0);
        }
    }
}